﻿//-----------------------------------------------------------------------
// <copyright file="ShellIconProvider.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>12/02/2013</date>
//-----------------------------------------------------------------------

using ConsoleHoster.Model.Entities;
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ConsoleHoster.Utilities
{
	internal sealed class ShellIconProvider : IExplorerItemIconProvider
	{
		public ImageSource GetIcon(ExplorerItem argItem)
		{
			string tmpExtension = argItem.ItemType == ExplorerItemType.Drive ? "[drive]" : argItem.ItemType == ExplorerItemType.Folder ? "[folder]" : Path.GetExtension(argItem.Path).ToLower();

			Icon tmpIcon = GetRawIcon(argItem.Path);

			return ToImageSource(tmpIcon);
		}

		private static Icon GetRawIcon(string argFilename)
		{
			SHFILEINFO tmpInfo = new SHFILEINFO();
			IntPtr tmpSmallImage = NativeMethods.SHGetFileInfo(argFilename, 0, ref tmpInfo, (uint)Marshal.SizeOf(tmpInfo), NativeMethods.SHGFI_ICON | NativeMethods.SHGFI_SMALLICON);

			Icon tmpResult = Icon.FromHandle(tmpInfo.hIcon).Clone() as Icon;
			NativeMethods.DestroyIcon(tmpInfo.hIcon);
			return tmpResult;
		}

		private ImageSource ToImageSource(Icon argIcon)
		{
			Bitmap tmpBitmap = argIcon.ToBitmap();
			IntPtr tmpHBitmap = tmpBitmap.GetHbitmap();

			ImageSource tmpResult = Imaging.CreateBitmapSourceFromHBitmap(
				tmpHBitmap,
				IntPtr.Zero,
				Int32Rect.Empty,
				BitmapSizeOptions.FromEmptyOptions());

			if (!NativeMethods.DeleteObject(tmpHBitmap))
			{
				throw new Exception("Failed to release resources assiociated with Icon handler");
			}

			return tmpResult;
		}

		[StructLayout(LayoutKind.Sequential)]
		private struct SHFILEINFO
		{
			public IntPtr hIcon;
			public IntPtr iIcon;
			public uint dwAttributes;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szDisplayName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
			public string szTypeName;
		};

		private class NativeMethods
		{
			public const uint SHGFI_ICON = 0x100;
			public const uint SHGFI_SMALLICON = 0x1;

			[DllImport("shell32.dll")]
			public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

			[DllImport("User32.dll")]
			public static extern int DestroyIcon(IntPtr hIcon);

			[DllImport("gdi32.dll", SetLastError = true)]
			public static extern bool DeleteObject(IntPtr hObject);
		}
	}
}
